package com.szxx.suit;

import java.util.List;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.szxx.domain.Cards;
import com.szxx.util.PokerUtil;

/**
 * 抽象牌型处理器 <br>
 * 子类应该是一个bean 来完成自动注册
 *
 * @author Ambrose
 */
public abstract class AbstractSuitAnalyzer<R extends AbstractAnalysisResult> {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private SuitAnalysisService suitAnalysisService;
	
	@PostConstruct
	public void init() {
		suitAnalysisService.register(this);
	}
	
	/**
	 * 处理器级别 <br>
	 */
	protected int getPriority() {
		return 0;
	}
	
	/**
	 * 分析器对应的对应牌型 <br>
	 */
	public abstract AbstractSuitType getSuitType();

	/**
	 * 是否符合牌型条件，如果符合填充分析结果 <br>
	 * 
	 * @param cards
	 * @param term
	 */
	public boolean match(Cards cards, AbstractSuitTerm term) {
		if (cards == null || cards.size() == 0) {
			return false;
		}
		// 工厂生成结果
		R result = getSuitResult();
		if (result == null) {
			return false;
		}
		// 填充分析结果
		cards.setResult(result);
		// 检查牌型
		if (!checkRule(cards, term)) {
//			cards.setResult(null); // 不符合就还原
			return false;
		}
		return true;
	}

	/**
	 * 分析结果
	 * 
	 * @return
	 */
	protected abstract R getSuitResult();
	
	/**
	 * 检查规则
	 * 
	 * @param cards
	 * @param term
	 * @return
	 */
	protected abstract boolean checkRule(Cards cards, AbstractSuitTerm term);
	
	/**
	 * 分析该牌列，在这个牌型下的大小权重
	 * 
	 * @param cards
	 * @param term
	 * @return
	 */
	protected abstract void analysize(Cards cards, AbstractSuitTerm term);
	
	/**
	 * 牌列整理
	 * 
	 * @param cards
	 * @param termCopy
	 */
	protected void sort(Cards cards, AbstractSuitTerm term) {
		PokerUtil.sortCards_asc(cards);
	}
	
	/**
	 * 填充癞子，仅当牌中含有癞子，且不全是癞子的时候会进入这里
	 * 
	 * @param cards
	 * @param term
	 * @param onlyMaxValue 仅赋值最大
	 */
	protected abstract List<Cards> analysizeLaizi(Cards cards, AbstractSuitTerm term, boolean onlyMaxValue);

	/**
	 * 提牌算法，从手牌中分析出对应可能符合牌型的牌出来 <br>
	 * 比如手牌 21QJ986554443 可以出的单牌就有 5 4 2 1 Q J 9 8 6 3 考虑拆牌
	 * 
	 * @param handCards
	 * @param term
	 * @param onlyMaxValue
	 * @return
	 */
	protected abstract List<Cards> listPossibleCards(Cards handCards, AbstractSuitTerm term);

}
